#include <iostream>
#include <assert.h>
#include <stdio.h>
#include <vector>
#include <boost/filesystem/operations.hpp>
#include "../org/vars.h"
#include "../org/audioinfo.h"
#include "../org/rule.h"
#include "../org/ruleio.h"
#include "../org/ruleinterpreter.h"
//#include "testsuite_lu.cpp"


#ifndef TEST_ORGANISER_RULES_PATH
#define TEST_ORGANISER_RULES_PATH "test_xml/test_organiser_rules.xml"
#endif

using namespace boost;
namespace bf = boost::filesystem;
using namespace Org;


void test_audio_info()
{
    cout << "\ntest_audio_info()...";
    assert(Org::AudioInfo::is_audio_file("test_files/test_id3.mp3"));
    assert(!Org::AudioInfo::is_audio_file("test_files/test_id3.txt"));

    Org::AudioInfo audio_info("test_files/test_id3.mp3");
    assert(audio_info.metadata["YEAR"] == "2010");
    assert(audio_info.metadata["TRACKNUMBER"] == "1");
    assert(audio_info.metadata["TITLE"] == "TEST_TITLE");
    assert(audio_info.metadata["ARTIST"] == "TEST_ARTIST");
    assert(audio_info.metadata["ALBUM"] == "TEST_ALBUM");
    assert(audio_info.metadata["GENRE"] == "Jungle");

    Org::AudioInfo audio_info_v1("test_files/test_id3_v1_only.mp3");
    assert(audio_info_v1.metadata["YEAR"] == "2010");
    assert(audio_info_v1.metadata["TRACKNUMBER"] == "1");
    assert(audio_info_v1.metadata["TITLE"] == "TEST_TITLE_V1");
    assert(audio_info_v1.metadata["ARTIST"] == "TEST_ARTIST_V1");
    assert(audio_info_v1.metadata["ALBUM"] == "TEST_ALBUM_V1");
    assert(audio_info_v1.metadata["GENRE"] == "Jungle");

    Org::AudioInfo audio_info_v2("test_files/test_id3_v2_only.mp3");
    assert(audio_info_v2.metadata["YEAR"] == "2010");
    assert(audio_info_v2.metadata["TRACKNUMBER"] == "1");
    assert(audio_info_v2.metadata["TITLE"] == "TEST_TITLE_V2");
    assert(audio_info_v2.metadata["ARTIST"] == "TEST_ARTIST_V2");
    assert(audio_info_v2.metadata["ALBUM"] == "TEST_ALBUM_V2");
    assert(audio_info_v2.metadata["GENRE"] == "Drum & Bass");
    cout << "[passed]" << endl;

}

void test_ruleio_parse_rules_file()
{
    /*
    Vars::map_action["copy"] = Vars::ORG_COPY;
    Vars::map_action["move"] = Vars::ORG_MOVE;
    Vars::map_action["delete"] = Vars::ORG_DELETE;
    Vars::map_action["copy_dir"] = Vars::ORG_COPY_DIR;

    cout << "\ntest_ruleio_parse_rules_file()...";
    Org::RuleIO rule_reader;
    vector<Rule> rules = rule_reader.parse_rules_file(TEST_ORGANISER_RULES_PATH);

    Rule first_rule = (Rule)rules.front();
    assert(first_rule.rule_name == "test_rule_alpha");   
    assert(first_rule.action == Vars::ORG_COPY);
    assert(first_rule.to_dir == "test/test_dir/Organised/UK_Hip_Hop");

    cout << "[passed]" << endl;
    */
}


void test_rule_io_parse_rulegroup_xml()
{

   cout << "test_rule_io_parse_rulegroup_xml()...";
   string rulegroups_xml =
       "<rulegroups>"
           "<rulegroup id=\"1\">"
                "<author>lusana</author>"
                "<name>Old skool labels + 1988 - 1993</name>"
                "<description>includes rules to map old skool labels with date range 1988-1993 to one directory</description>"
                "<date_inserted>01/01/1983</date_inserted>"
           "</rulegroup>"
       "</rulegroups>";

    vector<RuleGroup> rulegroups = Org::RuleIO::parse_rulegroup_xml(rulegroups_xml);

    assert(rulegroups.size() > 0);
    assert(rulegroups[0].author == "lusana");

    cout << "[passed]" << endl;
}


void test_rule_equals_operator()
{
    /*
    int id;
    bool enabled;
    string rule_name;
    string discogs_lookup; // eg. label/Def+Recordings
    Vars::e_action action; // COPY, MOVE, etc
    bf::path to_dir;
    */
    cout << "\ntest_rule_equals_operator()...";

    Rule rule1;
    rule1.id = 1;
    rule1.action = Vars::ORG_COPY;
    rule1.to_dir = boost::filesystem::path("/tmp/dest");
    rule1.root_node = new Node();

    Rule rule2;
    rule2.id = 1;
    rule2.action = Vars::ORG_MOVE;
    rule2.to_dir = boost::filesystem::path("/tmp/dest");
    rule2.root_node = new Node();

    assert(rule1 != rule2);

    rule2.action = Vars::ORG_COPY;

    assert(rule1 == rule2);


    /*
       rule1                rule2
         |                    |
        and                  and
       /   \                /   \
      c     or             c     c
          /    \
         c      c
    */

    Node r1a1;
    r1a1.node_type = Vars::ORG_NODE_BOOL;
    r1a1.operation = Vars::ORG_AND;

    Node r1o1;
    r1o1.node_type = Vars::ORG_NODE_BOOL;
    r1o1.operation = Vars::ORG_OR;

    r1a1.child_nodes.push_back(r1o1);

    Node r1c1;
    r1c1.node_type = Vars::ORG_NODE_CONDITION;
    r1c1.search_type = Vars::ORG_ID3;
    r1c1.search_in = "GENRE";

    r1a1.child_nodes.push_back(r1c1);

    Node r1c2;
    r1c2.node_type = Vars::ORG_NODE_CONDITION;
    r1c2.search_type = Vars::ORG_ID3;
    r1c2.search_in = "ALBUM";

    r1o1.child_nodes.push_back(r1c2);

    Node r1c3;
    r1c3.node_type = Vars::ORG_NODE_CONDITION;
    r1c3.search_type = Vars::ORG_ID3;
    r1c3.search_in = "ARTIST";

    r1o1.child_nodes.push_back(r1c3);

    // initial rule2 configuration
    Node diff_r2a1;
    diff_r2a1.node_type = Vars::ORG_NODE_BOOL;
    diff_r2a1.operation = Vars::ORG_AND;

    Node diff_r2c1;
    diff_r2c1.node_type = Vars::ORG_NODE_CONDITION;
    diff_r2c1.search_type = Vars::ORG_ID3;
    diff_r2c1.search_in = "GENRE";

    diff_r2a1.child_nodes.push_back(diff_r2c1);

    Node diff_r2c2;
    diff_r2c2.node_type = Vars::ORG_NODE_CONDITION;
    diff_r2c2.search_type = Vars::ORG_ID3;
    diff_r2c2.search_in = "ALBUM";

    diff_r2a1.child_nodes.push_back(diff_r2c2);

    rule1.root_node->child_nodes.push_back(r1a1);
    rule2.root_node->child_nodes.push_back(diff_r2a1);

    assert(rule1 != rule2);

    delete(rule2.root_node);

    rule2.root_node = new Node();

    // create rule2 configuration matching rule1
    Node r2a1;
    r2a1.node_type = Vars::ORG_NODE_BOOL;
    r2a1.operation = Vars::ORG_AND;

    Node r2o1;
    r2o1.node_type = Vars::ORG_NODE_BOOL;
    r2o1.operation = Vars::ORG_OR;

    r2a1.child_nodes.push_back(r2o1);

    Node r2c1;
    r2c1.node_type = Vars::ORG_NODE_CONDITION;
    r2c1.search_type = Vars::ORG_ID3;
    r2c1.search_in = "GENRE";

    r2a1.child_nodes.push_back(r2c1);

    Node r2c2;
    r2c2.node_type = Vars::ORG_NODE_CONDITION;
    r2c2.search_type = Vars::ORG_ID3;
    r2c2.search_in = "ALBUM";

    r2o1.child_nodes.push_back(r2c2);

    Node r2c3;
    r2c3.node_type = Vars::ORG_NODE_CONDITION;
    r2c3.search_type = Vars::ORG_ID3;
    r2c3.search_in = "ARTIST";

    r2o1.child_nodes.push_back(r2c3);

    rule2.root_node->child_nodes.push_back(r2a1);

    assert(rule1 == rule2);

    cout << "[passed]" << endl;
}

void test_read_and_write_xml()
{
    cout << "\ntest_read_and_write_xml()...";
    Org::RuleIO rule_io;
    vector<Rule> original_rules = rule_io.read_xml(TEST_ORGANISER_RULES_PATH);

    rule_io.write_xml(original_rules, "test_xml/new_test_organiser_rules.xml");
    vector<Rule> new_rules = rule_io.read_xml("test_xml/new_test_organiser_rules.xml");

    assert(original_rules.size() == new_rules.size());

    for (int i = 0; i < original_rules.size(); i++) {
        assert(original_rules[i] == new_rules[i]);
    }

    remove("test_xml/new_test_organiser_rules.xml");

    cout << "[passed]" << endl;
}

int main(int argc, char *argv[])
{

    test_audio_info();
    test_rule_equals_operator();
    test_read_and_write_xml();
    test_rule_equals_operator();
            
    
    //run_testsuite_lu();

    return 0;
}
